from flask import Flask, request
from werkzeug.contrib.fixers import ProxyFix
import time
from common import AuthException, calc_sign, ApiRespBase, NonceCache, LOG
from queue import Queue
from controler import Controler
import config

app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app)   # for nginx proxy
nonce_cache = NonceCache(config.request_timestamp_expire_time)
queue = Queue()
controler = Controler()


@app.errorhandler(Exception)
def exception_handle(e):
    resp = None
    if isinstance(e, AuthException):
        LOG.warning(e)
        resp = ApiRespBase.create_error_resp(500, str(e))
    else:
        LOG.exception(e)
        resp = ApiRespBase.create_error_resp(500, str(e))
    return str(resp)


@app.before_request
def check_author():
    path = request.path
    if path.startswith("/public/"):
        return
    isadmin_api = False
    if path.startswith("/api/admin/"):
        isadmin_api = True
    timestamp = request.args.get("timestamp", None)
    nonce = request.args.get("nonce", None)
    clientId = request.args.get("clientId", None)
    signClient = request.args.get("sign", None)
    if None in (timestamp, nonce, signClient, clientId):
        raise AuthException("认证信息缺失")
    now = int(time.time())
    if int(timestamp) + config.request_timestamp_expire_time < now:
        raise AuthException("时间戳过期")
    if int(timestamp) > now + config.request_timestamp_expire_time:
        raise AuthException("时间戳非法， 请调整客户端时间误差")
    # 检查是否存在
    if nonce_cache.is_key_exists(clientId, nonce):
        raise AuthException("nonce重复")
    _url = request.url
    url_root = request.url_root
    url_no_root = _url.replace(url_root, "/")
    index = url_no_root.find("&sign=")
    _url_need_sign = url_no_root[:index]
    signServer = calc_sign(_url_need_sign, isadmin=isadmin_api)
    if signClient != signServer:
        LOG.warning("signClient=" + signClient + " signServer=" + signServer)
        raise AuthException("sign校验失败")
    # 请求校验成功 把nonce记录下， 防止重放
    # 在校验sign之后再记录 可以防止拒绝服务攻击
    nonce_cache.record_nonce(clientId, nonce)


# @app.after_request
# def after_request(e):
#     return e


@app.route('/client/sync_data')
def cmd_get():
    humi = request.args.get("humi", None)
    temp = request.args.get("temp", None)
    block = request.args.get("block", "30")
    block = int(block)
    if block > 30:
        block = 30
    LOG.info("humi=" + str(humi) + " temp=" + str(temp))
    controler.record_info(humi, temp)
    return controler.get_cmd(timeout=block)


@app.route('/public/get_time')
def get_time():
    return str(int(time.time()))


@app.route('/api/admin/aircond/<cmd>')
def aircond_cmd(cmd: str):
    if cmd == "info":
        info = controler.get_airconf_info()
        return str(info)
    elif cmd == "on":
        controler.send_turn_on_cmd()
    elif cmd == "off":
        controler.send_turn_off_cmd()
    else:
        raise ValueError("unknow cmd")
    return "ok"


if __name__ == '__main__':
    app.run(host="0.0.0.0")
